package com.example.wnn.utils;

import com.example.wnn.config.aop.MyAnnotation;
import org.springframework.web.bind.annotation.PostMapping;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class AnnotationScannerUtils {

    public static Set<Class<?>> getClassesWithAnnotation(Class<?> annotationClass) {
        Set<Class<?>> classes = new HashSet<>();
        try {
            for (Class<?> clazz : getAllClasses()) {
                if (clazz.isAnnotationPresent((Class<Annotation>) annotationClass)) {
                    classes.add(clazz);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classes;
    }

    private static Set<Class<?>> getAllClasses() throws ClassNotFoundException {
        Set<Class<?>> classes = new HashSet<>();
        String packageName = "com.example.wnn.web.controller"; // 指定包名
        String packagePath = packageName.replace('.', '/');

        // 获取类路径，并在类路径下递归扫描所有文件和目录
        String[] classPaths = System.getProperty("java.class.path").split(File.pathSeparator);
        for (String classPath : classPaths) {
            File file = new File(classPath + File.separator + packagePath);
            recursiveScan(file, packageName, classes);
        }

        for (Class<?> clazz : classes) {
            System.out.println(clazz.getName());
        }
        return classes;
    }

    private static List<Class<?>> findClasses(Package pkg) throws IOException {
        List<Class<?>> classes = new ArrayList<Class<?>>();
        String packageName = pkg.getName();
        URL resource = ClassLoader.getSystemClassLoader().getResource(packageName.replace('.', '/'));
        if (resource.getProtocol().equals("file")) {
            try {
                classes.addAll(findClassesFromDirectory(new File(resource.toURI()), packageName));
            } catch (URISyntaxException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return classes;
    }

    private static void recursiveScan(File file, String packageName, Set<Class<?>> classes) {
        if (file.isDirectory()) {
            File[] subFiles = file.listFiles();
            if (subFiles != null) {
                for (File subFile : subFiles) {
                    recursiveScan(subFile, packageName + "." + subFile.getName(), classes);
                }
            }
        } else if (file.getName().endsWith(".class")) {
            try {
                String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
                Class<?> clazz = Class.forName(className);
                classes.add(clazz);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    private static List<Class<?>> findClassesFromDirectory(File directory, String packageName) throws ClassNotFoundException {
        List<Class<?>> classes = new ArrayList<Class<?>>();
        if (!directory.exists()) {
            return classes;
        }
        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                assert !file.getName().contains(".");
                classes.addAll(findClassesFromDirectory(file, packageName + "." + file.getName()));
            } else if (file.getName().endsWith(".class")) {
                classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
            }
        }
        return classes;
    }

    public static void main(String[] args) {
        Set<Class<?>> annotatedClasses = getClassesWithAnnotation(MyAnnotation.class);
        for (Class<?> clazz : annotatedClasses) {
            System.out.println(clazz.getName());
        }
    }
}
